/*
   \file AddRace.cpp
 *
   \date Jan 3, 2009
   \author Sarah Smith <sez@storybridge.org>
 */

#include "ui_addrace.h"
#include "AddRace.h"
#include "AddTrait.h"
#include "AddPower.h"
#include "LoadSave.h"

#include <Xml/XmlPath.h>
#include <Xml/XmlException.h>
#include <Models/DataListModel.h>
#include <Models/TraitListModel.h>

#include <QDebug>
#include <QTimer>
#include <QMessageBox>

struct RaceModels : public DialogModels
{
    RaceModels()
        : DialogModels()
        , mSkillsModel(0)
        , mLanguagesModel(0)
        , mAbilitiesModel(0)
        , mTraitsModel(0)
        , mPowersModel(0)
    {
    }
    ~RaceModels()
    {
        delete mSkillsModel;
        delete mLanguagesModel;
        delete mAbilitiesModel;
        delete mTraitsModel;
        delete mPowersModel;
    }
    SkillsModel *mSkillsModel;
    LanguagesModel *mLanguagesModel;
    AbilitiesModel *mAbilitiesModel;
    TraitModel *mTraitsModel;
    PowerModel *mPowersModel;
};

/*!
   \class AddRaceDialog
   \brief Implementation of AddUpdateDialog to manage Race data.
   \sa AddUpdateDialog()
 */

/*!
   \fn AddRaceDialog::AddRaceDialog(const XmlPath &title, QWidget *parent)
   \override
 */

AddRaceDialog::AddRaceDialog(QWidget *parent)
    : AddUpdateDialog(XmlPath(XmlPath::RACIAL_BASE), parent)
    , mAddRace(new Ui::AddRaceDialog())
    , mData(0)
    , mModels(new RaceModels())
{
    mAddRace->setupUi(this);
}

/*
   \brief Destroy this dialog, releasing any resources.
   \details Note that the internal Race object, returned by the data()
   function, is destroyed here.
 */
AddRaceDialog::~AddRaceDialog()
{
    delete mAddRace;
    delete mData;
    delete mModels;
}

/*!
  \brief Return the instance of the AddRaceDialog dialog.
  This method is first called during the construction of the QMainWindow,
  and at this time the instance is initialized with the main window as its
  \a parent.  With this invariant, the method is thread-safe, otherwise it
  is not.  On subsequent calls the already initialized instance is returned
  and any argument is ignored.
 */
AddRaceDialog *AddRaceDialog::dialog(QWidget *parent)
{
    static AddRaceDialog *dlg = 0;
    if (dlg == 0)
        dlg = new AddRaceDialog(parent);
    return dlg;
}

/*!
   \brief Retrieve the Race data from this dialog.
 */
TitledData *AddRaceDialog::data()
{
    if (mData == 0)
        mData = new Race(xmlPath().typeName());
    return mData;
}

/*!
   \override
 */
void AddRaceDialog::setupData()
{
    mAddRace->sizeComboBox->clear();
    for (int i = 0; i < DndData::NUM_SIZES; ++i)
        mAddRace->sizeComboBox->addItem(DndData::SIZE_NAMES[i]);
    mAddRace->sizeComboBox->setCurrentIndex(0);
    mAddRace->visionComboBox->clear();
    for (int i = 0; i < DndData::NUM_VISION_TYPES; ++i)
        mAddRace->visionComboBox->addItem(DndData::VISION_TYPES[i]);
    mAddRace->visionComboBox->setCurrentIndex(0);

    if (!mModels->mInitialized)
    {
        mModels->mSkillsModel = makeSkillsModel(this);
        mModels->mLanguagesModel = makeLanguagesModel(this);
        mModels->mAbilitiesModel = makeAbilitiesModel(this);

        mAddRace->skillsListView->setModel(mModels->mSkillsModel);
        mAddRace->languagesListView->setModel(mModels->mLanguagesModel);
        mAddRace->abilitiesListView->setModel(mModels->mAbilitiesModel);
        mModels->mInitialized = true;
    }

    delete mModels->mTraitsModel;
    mModels->mTraitsModel = makeTraitModel(xmlPath(), this);
    delete mModels->mPowersModel;
    mModels->mPowersModel = makePowerModel(xmlPath(), this);
    mAddRace->traitsListView->setModel(mModels->mTraitsModel);
    mAddRace->powersListView->setModel(mModels->mPowersModel);

    mAddRace->summaryLineEdit->setText(tr("Summary"));
    mAddRace->titleLabel->setText(xmlPath().typeName());
}

/*!
   \override
 */
void AddRaceDialog::loadData()
{
    Q_ASSERT(mData);
    mAddRace->minHeightSpinBox->setValue(mData->heightMin);
    mAddRace->maxHeightSpinBox->setValue(mData->heightMax);
    mAddRace->minWeightSpinBox->setValue(mData->weightMin);
    mAddRace->maxWeightSpinBox->setValue(mData->weightMax);
    mAddRace->sizeComboBox->setCurrentIndex(mData->size);
    mAddRace->speedSpinBox->setValue(mData->speed);
    mAddRace->visionComboBox->setCurrentIndex(mData->vision);
    mAddRace->summaryLineEdit->setText(mData->raceSummary);
    mModels->mSkillsModel->setSelected(mData->skillBonus);
    mModels->mAbilitiesModel->setSelected(mData->abilityBonus);
    mModels->mLanguagesModel->setSelected(mData->language);
    mModels->mTraitsModel->setSelected(mData->traits);
    mModels->mPowersModel->setSelected(mData->powers);
}

void AddRaceDialog::clearData()
{
    mAddRace->minHeightSpinBox->setValue(0);
    mAddRace->maxHeightSpinBox->setValue(99);
    mAddRace->minWeightSpinBox->setValue(0);
    mAddRace->maxWeightSpinBox->setValue(99);
    mAddRace->sizeComboBox->setCurrentIndex(DndData::MEDIUM_SIZE);
    mAddRace->speedSpinBox->setValue(5);
    mAddRace->visionComboBox->setCurrentIndex(DndData::NORMAL_VISION);
    mAddRace->summaryLineEdit->setText("");
    mModels->mSkillsModel->setSelected(QList<DndData::SkillTypes>());
    mModels->mAbilitiesModel->setSelected(QList<DndData::Ability>());
    mModels->mLanguagesModel->setSelected(QList<DndData::Language>());
    mModels->mTraitsModel->setSelected(QList<Trait>());
    mModels->mPowersModel->setSelected(QList<Power>());
}

/*!
   \override
 */
void AddRaceDialog::saveData()
{
    Q_ASSERT(mData);
    mData->heightMin = mAddRace->minHeightSpinBox->value();
    mData->heightMax = mAddRace->maxHeightSpinBox->value();
    mData->weightMin = mAddRace->minWeightSpinBox->value();
    mData->weightMax = mAddRace->maxWeightSpinBox->value();
    int sizeCode = mAddRace->sizeComboBox->currentIndex();
    mData->size = static_cast<DndData::BodySize>(sizeCode);
    mData->speed = mAddRace->speedSpinBox->value();
    int visionCode = mAddRace->visionComboBox->currentIndex();
    mData->raceSummary = mAddRace->summaryLineEdit->text();
    mData->vision = static_cast<DndData::VisionType>(visionCode);
    mData->skillBonus = mModels->mSkillsModel->selected();
    mData->language = mModels->mLanguagesModel->selected();
    mData->abilityBonus = mModels->mAbilitiesModel->selected();
    mData->traits = mModels->mTraitsModel->selected();
    mData->powers = mModels->mPowersModel->selected();
    mData->raceDescription = mAddRace->descriptionTextEdit->toPlainText();
}

void AddRaceDialog::on_powerPushButton_clicked(bool)
{
    XmlPath xp(xmlPath());
    xp.setSubType(XmlPath::POWER_TYPE);
    AddPower *dlg = AddPower::dialog();
    dlg->setXmlPath(xp);
    dlg->show();
    dlg->raise();
    dlg->activateWindow();
    dlg->initialize();
}

void AddRaceDialog::on_traitPushButton_clicked(bool)
{
    XmlPath xp(xmlPath());
    xp.setSubType(XmlPath::TRAIT_TYPE);
    AddTrait *dlg = AddTrait::dialog();
    dlg->setXmlPath(xp);
    dlg->show();
    dlg->raise();
    dlg->activateWindow();
    dlg->initialize();
}
